#pragma once

#include <iostream>
#include <string>
#include <time.h>
#include <cstdio>
#include "Mutex.hpp"
#include <filesystem> // C++17,方便文件管理
#include <fstream>    // 方便文件内容的操作
#include <sstream>
#include <memory>
#include <sys/types.h>
#include <unistd.h>

namespace LogModule
{
    using namespace MutexModule;

    std::string GetTime()
    {
        time_t curr = time(nullptr);
        struct tm curr_tm;
        localtime_r(&curr, &curr_tm);
        char time_str[128];
        snprintf(time_str, sizeof(time_str), "%4d-%02d-%02d %02d:%02d:%02d",
                 curr_tm.tm_year + 1900,
                 curr_tm.tm_mon + 1,
                 curr_tm.tm_mday,
                 curr_tm.tm_hour,
                 curr_tm.tm_min,
                 curr_tm.tm_sec);
        return time_str;
    }

    enum class LogLevel
    {
        DEBUG,
        INFO,
        WARNING,
        ERROR,
        FATAL
    };

    std::string LogLeveltoString(LogLevel log_level)
    {
        if (log_level == LogLevel::DEBUG)
            return "DEBUG";
        else if (log_level == LogLevel::INFO)
            return "INFO";
        else if (log_level == LogLevel::WARNING)
            return "WARNING";
        else if (log_level == LogLevel::ERROR)
            return "ERROR";
        else if (log_level == LogLevel::FATAL)
            return "FATAL";
        else
            return "UNKNOWN";
    }

    class LogStrategy
    {
    public:
        virtual void SyncLog(const std::string &message) = 0; // 纯虚函数，不需要实现，不能创建对象
    };

    class ConsoleLogStrategy : public LogStrategy
    {
    public:
        virtual void SyncLog(const std::string &message) override
        {
            LockGuard lockguard(_mutex);
            std::cout << message << std::endl;
        }

    private:
        Mutex _mutex;
    };

    const std::string default_path = "/var/log/"; // / 是系统 “核心区”，放不动的关键文件
    const std::string default_name = "my.log";
    const std::string gsep = "\r\n"; // 全局的分隔符
    class FileLogStrategy : public LogStrategy
    {
    public:
        FileLogStrategy(const std::string &file_path = default_path,
                        const std::string &file_name = default_name)
            : _file_path(file_path), _file_name(file_name)
        {
            LockGuard lockguard(_mutex);
            if (std::filesystem::exists(_file_path))
            {
                return;
            }
            try
            {
                std::filesystem::create_directories(_file_path);
            }
            catch (const std::filesystem::filesystem_error &e)
            {
                std::cerr << e.what() << '\n';
            }
        }
        virtual void SyncLog(const std::string &message) override
        {
            LockGuard lockguard(_mutex);
            std::string file_path_name = _file_path + (_file_path.back() == '/' ? "" : "/") + _file_name;

            std::ofstream out(file_path_name, std::ios::app); // 以追加写入的方式打开
            if (!out.is_open())
            {
                return;
            }
            out << message << gsep;
        }

    public:
        std::string _file_path;
        std::string _file_name;
        Mutex _mutex;
    };

    class Logger
    {
    public:
        Logger()
        {
            EnableConsoleLogStrategy();
        }

        void EnableConsoleLogStrategy()
        {
            _fflush_strategy = std::make_unique<ConsoleLogStrategy>();
        }

        void EnableFileLogStrategy()
        {
            _fflush_strategy = std::make_unique<FileLogStrategy>();
        }

        class LogMessage
        {
        public:
            LogMessage(LogLevel log_level, const std::string &file_name, int line_number, const Logger *logger)
                : _logger(logger)
            {
                std::stringstream ss;
                ss << "[" << GetTime() << "] "
                   << "[" << LogLeveltoString(log_level) << "] "
                   << "[" << getpid() << "] "
                   << "[" << file_name << "] "
                   << "[" << line_number << "] - ";
                _message = ss.str();
            }

            template <typename T>
            LogMessage& operator<<(const T &info)
            {
                std::stringstream ss;
                ss << info;
                _message += ss.str();
                return *this;
            }

            ~LogMessage()
            {
                if (_logger->_fflush_strategy)
                {
                    _logger->_fflush_strategy->SyncLog(_message);
                }
            }

        private:
            std::string _message;
            const Logger *_logger;
        };

        LogMessage operator()(LogLevel log_level, const std::string &file_name, int line_number)
        {
            return LogMessage(log_level, file_name, line_number, this);
        }

    private:
        std::unique_ptr<LogStrategy> _fflush_strategy = nullptr;
    };

    // 全局日志对象
    Logger logger;

// 使用宏，简化用户操作，获取文件名和行号
#define LOG(level) logger(level, __FILE__, __LINE__)
#define Enable_Console_Log_Strategy() logger.EnableConsoleLogStrategy()
#define Enable_File_Log_Strategy() logger.EnableFileLogStrategy()
}